package com.gitee.wsl.prism4j.languages

import com.gitee.wsl.prism4j.GrammarUtils
import com.gitee.wsl.prism4j.GrammarUtils.findFirstInsideGrammar
import com.gitee.wsl.prism4j.GrammarUtils.findToken
import com.gitee.wsl.prism4j.GrammarUtils.require
import com.gitee.wsl.prism4j.Prism4j
import com.gitee.wsl.prism4j.Prism4j.Companion.grammar
import com.gitee.wsl.prism4j.Prism4j.Companion.pattern
import com.gitee.wsl.prism4j.Prism4j.Companion.token
import com.gitee.wsl.prism4j.annotations.Extend
import com.gitee.wsl.prism4j.Prism4j.Pattern

@Suppress("unused")
@Extend("clike")
object Prism_swift {
    fun create(prism4j: Prism4j): Prism4j.Grammar {
        val swift: Prism4j.Grammar = GrammarUtils.extend(
            require(prism4j, "clike"),
            "swift",
            token(
                "string", pattern(
                    Pattern.compile("(\"|')(\\\\(?:\\((?:[^()]|\\([^)]+\\))+\\)|\\r\\n|[\\s\\S])|(?!\\1)[^\\\\\\r\\n])*\\1"),
                    false,
                    true,
                    null,
                    grammar(
                        "inside", token(
                            "interpolation", pattern(
                                Pattern.compile("\\\\\\((?:[^()]|\\([^)]+\\))+\\)"),
                                false,
                                false,
                                null,
                                grammar(
                                    "inside", token(
                                        "delimiter", pattern(
                                            Pattern.compile("^\\\\\\(|\\)$"),
                                            false,
                                            false,
                                            "variable"
                                        )
                                    )
                                )
                            )
                        )
                    )
                )
            ),
            token(
                "keyword", pattern(
                    Pattern.compile("\\b(?:as|associativity|break|case|catch|class|continue|convenience|default|defer|deinit|didSet|do|dynamic(?:Type)?|else|enum|extension|fallthrough|final|for|func|get|guard|if|import|in|infix|init|inout|internal|is|lazy|left|let|mutating|new|none|nonmutating|operator|optional|override|postfix|precedence|prefix|private|protocol|public|repeat|required|rethrows|return|right|safe|self|Self|set|static|struct|subscript|super|switch|throws?|try|Type|typealias|unowned|unsafe|var|weak|where|while|willSet|__(?:COLUMN__|FILE__|FUNCTION__|LINE__))\\b")
                )
            ),
            token(
                "number", pattern(
                    Pattern.compile(
                        "\\b(?:[\\d_]+(?:\\.[\\de_]+)?|0x[a-f0-9_]+(?:\\.[a-f0-9p_]+)?|0b[01_]+|0o[0-7_]+)\\b",
                        Pattern.CASE_INSENSITIVE
                    )
                )
            )
        )

        val tokens: MutableList<Prism4j.Token> = swift.tokens()

        tokens.add(token("constant", pattern(Pattern.compile("\\b(?:nil|[A-Z_]{2,}|k[A-Z][A-Za-z_]+)\\b"))))
        tokens.add(
            token(
                "atrule",
                pattern(Pattern.compile("@\\b(?:IB(?:Outlet|Designable|Action|Inspectable)|class_protocol|exported|noreturn|NS(?:Copying|Managed)|objc|UIApplicationMain|auto_closure)\\b"))
            )
        )
        tokens.add(
            token(
                "builtin",
                pattern(Pattern.compile("\\b(?:[A-Z]\\S+|abs|advance|alignof(?:Value)?|assert|contains|count(?:Elements)?|debugPrint(?:ln)?|distance|drop(?:First|Last)|dump|enumerate|equal|filter|find|first|getVaList|indices|isEmpty|join|last|lexicographicalCompare|map|max(?:Element)?|min(?:Element)?|numericCast|overlaps|partition|print(?:ln)?|reduce|reflect|reverse|sizeof(?:Value)?|sort(?:ed)?|split|startsWith|stride(?:of(?:Value)?)?|suffix|swap|toDebugString|toString|transcode|underestimateCount|unsafeBitCast|with(?:ExtendedLifetime|Unsafe(?:MutablePointers?|Pointers?)|VaList))\\b"))
            )
        )

        val interpolationToken = findToken(swift, "string/interpolation")
        val interpolationGrammar = if (interpolationToken != null)
            findFirstInsideGrammar(interpolationToken)
        else
            null

        interpolationGrammar?.tokens()?.addAll(swift.tokens())

        return swift
    }
}
